import { join } from 'path';
import { outputFileSync } from 'fs-extra';
import { Compiler, TranspileOutput, TranspileOpts } from '@teambit/compiler';
import { BuiltTaskResult, BuildContext } from '@teambit/builder';
import { compileSync } from '@teambit/modules.mdx-compiler';

export class MDXCompiler implements Compiler {
  displayName = 'MDX';

  shouldCopyNonSupportedFiles = true;

  distDir = 'dist';

  constructor(readonly id: string, readonly config: any) {}

  displayConfig() {
    return JSON.stringify(this.config, null, 2);
  }

  transpileFile(fileContent: string, options: TranspileOpts): TranspileOutput {
    const output = compileSync(fileContent, {
      filepath: options.filePath,
      // this compiler is not indented to compile according to the bit flavour.
      bitFlavour: false,
    });

    return [
      {
        outputText: output.contents,
        outputPath: this.getDistPathBySrcPath(options.filePath),
      },
    ];
  }

  /**
   * compile components inside isolated capsules. this being used during tag for the release.
   * meaning, the final package of the component has the dists generated by this method.
   */
  async build(context: BuildContext): Promise<BuiltTaskResult> {
    const capsules = context.capsuleNetwork.seedersCapsules;
    const componentsResults = capsules.map((capsule) => {
      const srcFiles = capsule.component.filesystem.files.filter((file) => {
        return this.isFileSupported(file.relative);
      });

      const errors = srcFiles.map((srcFile) => {
        try {
          const output = compileSync(srcFile.contents.toString('utf-8'));
          outputFileSync(join(capsule.path, 'dist', this.getDistPathBySrcPath(srcFile.path)), output.contents);
          return undefined;
        } catch (err) {
          return err;
        }
      });

      return {
        errors: errors.filter((err) => !!err),
        component: capsule.component,
      };
    });

    return {
      componentsResults,
      artifacts: [
        {
          name: 'dist',
          globPatterns: [`${this.distDir}/**`],
        },
      ],
    };
  }

  /**
   * given a source file, return its parallel in the dists. e.g. "index.ts" => "dist/index.js"
   * both, the return path and the given path are relative paths.
   */
  getDistPathBySrcPath(srcPath: string): string {
    return join(srcPath.replace('.mdx', '.js'));
  }

  /**
   * only supported files matching get compiled. others, are copied to the dist dir.
   */
  isFileSupported(filePath: string): boolean {
    return filePath.endsWith('.mdx') || filePath.endsWith('.md');
  }

  /**
   * returns the version of the current compiler instance (e.g. '4.0.1').
   */
  version(): string {
    return '';
  }
}
